#include <error.h>
#include <assert.h>
#include <malloc.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>


#include "conf.h"
#include "common.h"




extern void *alloc_block (size_t sz)
{


        void * memory;
        size_t alloc_size;

        assert(sz > 0);

        if (sz <= CPU_CACHE_LINE_SIZE) {
                alloc_size = CPU_CACHE_LINE_SIZE;
        }
        else if ((sz & (CPU_CACHE_LINE_SIZE-1)) == 0){
                alloc_size = sz;
        }
        else{
                alloc_size = ((sz & (~(CPU_CACHE_LINE_SIZE - 1)))
                              + CPU_CACHE_LINE_SIZE);
        }

        memory = memalign(CPU_CACHE_LINE_SIZE, alloc_size);
        return memory;
}


extern void *realloc_block(void*ptr, size_t sz)
{
        void *memory;
        size_t alloc_size;


        
        if (NULL == ptr) {
                return alloc_block(sz);
        }

        if (sz == 0 && NULL != ptr) {
                free_block(ptr);
                return NULL;
        }


        memory = alloc_block(sz);
        if (NULL != memory) {
                memcpy(memory, ptr, sz);
                return memory;
        }
        else {
                return NULL;
        }
}

extern void free_block(void *ptr)
{
        free(ptr);
}



extern void set_socket_nonblock(int fd)
{
        assert(fd >= 0);

        int flag;


        flag = fcntl(fd, F_GETFL, NULL);
        flag |= O_NONBLOCK;
        fcntl(fd, F_SETFL, flag);
}


extern void set_tcp_socket_nodelay(int fd)
{
        int yes = 1;
        
        assert(fd >= 0);

        
        setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(int));
}


extern void set_tcp_socket_quickack(int fd)
{
        int yes = 1;

        assert(fd >= 0);

        setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &yes, sizeof(int));
}




extern void set_tcp_socket_keepalive_count(int fd)
{
        int count = 3;

        assert(fd >= 0);

        setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(int));
}



extern void set_tcp_socket_keepalive_interval(int fd, int interval)
{
        int yes = 1;

        assert(fd >= 0);

        setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(int));
}

extern void set_socket_reuse_address(int fd)
{
        int yes = 1;

        assert(fd >= 0);
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}


extern void set_socket_disable_linger(int fd)
{
        struct linger linger;


        memset(&linger, 0, sizeof(struct linger));
        linger.l_onoff = 0;
        linger.l_linger = 0;
        setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger));
}



extern int get_cpu_count ()
{
        int cpu_count;


        cpu_count = sysconf(_SC_NPROCESSORS_ONLN);
        return cpu_count;
}




extern int get_socket_unread_data_size(int fd, int *unread_data_size)
{

        int ret;

        
        *unread_data_size = 0;

        ret = ioctl(fd, FIONREAD, unread_data_size);
        return ret;
}
        


extern int peek_socket_data(int fd, void *buffer, size_t size)
{
        int ret;


        ret = recv(fd, buffer, size, MSG_PEEK);
        return ret;
}

